#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Web presentation DataGroup, UserGroupPerm classes"""

from django import template
from django import http
from django.shortcuts import render_to_response, redirect, get_object_or_404
#                             get_list_or_404, , HttpResponse
from django.utils.translation import ugettext as _
#from django.utils.decorators import method_decorator
#from django.views.decorators.cache import cache_control
from django.views.decorators.cache import never_cache

#from django.views.decorators.csrf import csrf_protect
from django.contrib.auth.decorators import login_required
from django.forms import models as model_forms
#from django import forms

from django.contrib import messages
from django.contrib.auth.models import User, Group
#from django.db import transaction
from django.db.models import Q
from django.db import connection
from django.views.generic import ListView, CreateView, UpdateView
import datetime
from copy import copy
from importlib import import_module

#------------------------------------------------------------------------------
#for debug purpose
def show(obj):
    '''Debugging tool: show everything about obj'''
    print 'show_obj:', obj
    for ind in dir(obj):
        print '  show_dir(obj):', ind, ':', getattr(obj, ind)

#------------------------------------------------------------------------------
def prevpage(request):
    "Come back to the same page after an action"

    next_url = request.REQUEST.get('next', None)
    if not next_url:
        next_url = request.META.get('HTTP_REFERER', None)
    if not next_url:
        next_url = '/'
    return http.HttpResponseRedirect(next_url)

#------------------------------------------------------------------------------
def class_by_name(classname):
    "Import a class by its name from corresponding directory"

    import labman2.data.models as base_mod
    if hasattr(base_mod, classname):
        class_inst = getattr(base_mod, classname)
    else:
        tmp_name = '.' + classname
        try:
            mod = import_module(tmp_name, 'labman2.data.subdata')
            tmp_mod = getattr(mod, 'models')
            class_inst = getattr(tmp_mod, classname)
        except ImportError as err:
            raise ImportError("Could not import module %s: %s" % (
                                                               classname, err))
    return class_inst

#------------------------------------------------------------------------------
def set_desktop(request):
    'Setup items on desktop'

    response = prevpage(request)
    if request.POST:
        check_list = [elem for elem in request.POST.items()
                                    if str(elem[0]).startswith('obj_desk_')]
        gr_list = [elem for elem in request.POST.items()
                                    if str(elem[0]).startswith('gr_desk_')]
        cls_list = [elem for elem in request.POST.items()
                                    if str(elem[0]).startswith('cls_desk_')]
        if (request.POST.has_key('delete') and
                request.POST['delete'] == _('Remove from desktop')):
            if (len(check_list) >= 1 or len(gr_list) >= 1 or
                                                        len(cls_list) >= 1):
                if len(check_list) >= 1:
                    for elem in check_list:
                        class_by_name('DeskTop').objects.filter(
                                                           pk=elem[1]).delete()
                    messages.add_message(request, messages.SUCCESS,
                    _('Items successfully deleted from desktop (kept in DB).'))
                if len(gr_list) >= 1:
                    for elem in gr_list:
                        class_by_name('GroupDeskTop').objects.filter(
                                                           pk=elem[1]).delete()
                    messages.add_message(request, messages.SUCCESS,
                   _('Groups successfully deleted from desktop (and in DB).'))
                if len(cls_list) >= 1:
                    for elem in cls_list:
                        class_by_name('ClassDeskTop').objects.filter(
                                                           pk=elem[1]).delete()
                    messages.add_message(request, messages.SUCCESS,
                   _('Classess deleted from desktop (and in DB).'))
            else:
                messages.add_message(request, messages.WARNING,
          _('At least one item should be selected for removing from desktop.'))

    return response

#------------------------------------------------------------------------------
def add_obj_desktop(request, tablename):
    'Add group or data on desktop'

    if tablename == 'GroupDeskTop':
        objkey = 'group_id'
    if tablename == 'DeskTop':
        objkey = 'base_id'
    if tablename == 'ClassDeskTop':
        objkey = 'classname_id'
    response = prevpage(request)

    if request.POST:
        obj_list = [elem for elem in request.POST.items()
                                    if str(elem[0]).startswith('obj_to_desk_')]
        if (request.POST.has_key('add_obj_on_desktop') and
                request.POST['add_obj_on_desktop'] == _('Add to DeskTop')):
            if len(obj_list) >= 1:
                for elem in obj_list:
                    kwargs = {'user_id': request.user.id, objkey: elem[1]}
                    class_by_name(tablename)( # pylint: disable=W0142
                                             **kwargs).save()
                messages.add_message(request, messages.SUCCESS,
               _('Data successfully added on desktop.'))
            else:
                messages.add_message(request, messages.WARNING,
              _('At least one item should be selected for adding on desktop.'))

    return response

#------------------------------------------------------------------------------
def desktoplist(request):
    "Return list of pairs (base_obj, real_obj) data to be presented on desktop"

    obj_list = [(elem, class_by_name(class_by_name('Base').objects.get(
                    pk=elem.base_id).classname_id).objects.get(id=elem.base_id))
                  for elem in class_by_name('DeskTop').objects.filter(
                                                          user=request.user.id)]
    return obj_list

#------------------------------------------------------------------------------
def group_desktoplist(request):
    "Return list of group which will be presented in desktop area"

    gr_list = class_by_name('GroupDeskTop').objects.filter(
                                                          user=request.user.id)
    return gr_list

#------------------------------------------------------------------------------
def classes_desktop(request):
    "Return list of classes which will be presented in desktop area"
    cls_list = class_by_name('ClassDeskTop').objects.filter(
                                                          user=request.user.id)
    return cls_list

#------------------------------------------------------------------------------
def mark_save_links(request, lnk_list, obj_id, new_data):
    """Mark links as deleted, save them and return list of new links.
       For LinkType: mark links as deleted. New links for new
       LinkType can not be created/edited automatically and should be
       created/edited separately on the add/edit Link page.
    """

    new_links_list = []
    link_data = {'created_by_id': request.user.username,
                 'classname_id': 'Link'}
    for elem in lnk_list:
        elem.deleted_on = datetime.datetime.now()
        elem.deleted_by_id = request.user.username
        elem.save()
        if elem.link_type_id == obj_id:
            continue
        if elem.subject_id == obj_id:
            link_data.update({'subject': new_data,
                              'property': elem.property,
                              'link_type': elem.link_type})
        if elem.property_id == obj_id:
            link_data.update({'subject': elem.subject,
                              'property': new_data,
                              'link_type': elem.link_type})
        new_link = class_by_name('Link').objects.create( # pylint: disable=W0142
                                                        **link_data)
        new_links_list.append(new_link)

    return new_links_list

#------------------------------------------------------------------------------
#@cache_control(must_revalidate=True, max_age=3600)
#@csrf_protect
@login_required
def openform(request, act):
    """Redirect to the page according to select form"""

    if request.method == 'POST':
        if act == 'add':
            return redirect('/add/' + request.POST['dtform'] +'/')
        elif act == 'usage':
            return redirect('/' + request.POST['btusage'].lower() + \
                                  request.POST['dtform'])

    messages.add_message(request, messages.ERROR, _('POST request expected'))
    return redirect('/')

#------------------------------------------------------------------------------
def general_context(request, title=None, content_title=None):
    "Return general context for rendering on the web pages"


    cls_dt = classes_desktop(request)
    return {'title': _(title), 'content_title': _(content_title),
            'dataforms': [(elem.classname, elem.classname) for elem in cls_dt],
            'desktop_list': desktoplist(request),
            'mygroups_desktop': group_desktoplist(request),
            'classes_desktop': cls_dt,
            'connect': connection.queries,
           }

#------------------------------------------------------------------------------
def save_data_ondesktop(request, obj):
    "Save adding data on desktop"

    dt_data = {'base': obj, 'user': request.user}
    class_by_name('DeskTop')(**dt_data).save() # pylint: disable=W0142

#------------------------------------------------------------------------------
def save_data_ingroups(request, gr_list, obj, lnk_list=None):
    "Save added/edited data in user's groups"

    for grp in gr_list:
        class_by_name('DataGroup')(group=grp, data=obj,
                   created_by_id=request.user, classname_id='DataGroup').save()
        if lnk_list:
            for link in lnk_list:
                class_by_name('DataGroup')(group=grp, data=link,
                          created_by_id=request.user,
                          classname_id='DataGroup').save()
#------------------------------------------------------------------------------
def restore(request, fmname, pk): #pylint: disable=C0103
    "Marked as deleted data is not changed. New data will be created as a copy"

    def save_new_obj(request, gr_list, obj, fmname):
        "Save object in all needed places"

        kwargs = copy(obj.__dict__)
        for elem in kwargs.keys():
            if elem.startswith('_'): # _state, _*_cache etc.
                del kwargs[elem]
        del kwargs['id']
        del kwargs['base_ptr_id']
        kwargs['deleted_on'] = None
        kwargs['deleted_by_id'] = None
        kwargs['created_by_id'] = request.user.username
        new_obj = class_by_name(fmname).objects.create( # pylint: disable=W0142
                                                       **kwargs)
        #save data in the same groups as deleted data
        save_data_ingroups(request, gr_list, new_obj)
        #save data on desktop
        save_data_ondesktop(request, new_obj)
        return new_obj

    obj = class_by_name(fmname).objects.get(pk=pk)

    if fmname == 'Link' and ((obj.subject and obj.subject.deleted_by) or
                             (obj.property and obj.property.deleted_by) or
                              obj.link_type.deleted_by):
        if obj.subject.deleted_by:
            real_subj = class_by_name(obj.subject.classname.classname
                        ).objects.get(id=obj.subject.id)
            messages.add_message(request, messages.INFO,
                _('Subject <a href = "/base/%s/">%s</a>'
                  ' should be restored in advance.')
                % (obj.subject.id, real_subj))
        if obj.property.deleted_by:
            real_property = class_by_name(obj.property.classname.classname
                                            ).objects.get(id=obj.property.id)
            messages.add_message(request, messages.INFO,
                _('Property <a href = "/base/%s/">%s</a>'
                  ' should be restored in advance.')
                % (obj.property.id, real_property))
        if obj.link_type.deleted_by:
            messages.add_message(request, messages.INFO,
                _('Link Type <a href = "/base/%s/">%s</a>'
                  ' should be restored in advance.')
                % (obj.link_type.id, obj.link_type.link_type))
        return redirect('/base/%s/' % pk)

    new_objs = [copy(elem) for elem in
                class_by_name('Link').objects.filter(Q(subject=pk) | \
                                        Q(property=pk) | Q(link_type=pk))]
    new_objs.insert(0, copy(obj))
    groups_list = [elem.group for elem in
                               class_by_name('DataGroup').objects. \
                                                            filter(data=obj)]

    #BEGIN
    #transaction.atomic
    try:
        new_obj = save_new_obj(request, groups_list, new_objs[0], fmname)
        for elem in new_objs[1:]:
            if elem.subject and elem.subject.id == obj.id:
                elem.subject = new_obj
            if elem.property and elem.property.id == obj.id:
                elem.property = new_obj
            if elem.link_type == obj.id:
                elem.link_type = new_obj
            elem.save()
    except StandardError:
        import sys
        messages.add_message(request, messages.ERROR,
            _('Restore ERROR: ') + str(sys.exc_info()[1]))
        return redirect('/base/%s/' % pk)
    #COMMIT
    messages.add_message(request, messages.INFO,
                        _(u"%s has been restored from data %s."
                             %(new_obj, obj)))
    return redirect('/edit/%s/%s/' % (fmname, new_obj.id))

#------------------------------------------------------------------------------
# pylint: disable=R0901,R0904
class BaseCreateView(CreateView):
    'Generate forms for creating new data items'


    def get_form_class(self):
        'Make a form from a class'

        model = class_by_name(self.kwargs['fmname']) # pylint: disable=E1101
        form = model_forms.modelform_factory(model)

        # change help_text for fields in derived class, i.e in ReSt class and
        # derived from it
        class_list = [model]
        class_list.extend(model._meta.get_parent_list()) # pylint: disable=W0212
        for mod in class_list:
            opts = mod._meta # pylint: disable=W0212
            if hasattr(opts, 'help_texts'):
                for key, value in opts.help_texts.iteritems():
                    form.base_fields[key].help_text = value
                return form

        return form

    def get_success_url(self):
        'Prepare the next page url'

        if self.object:
            url = '/edit/%s/%s/' % (self.kwargs['fmname'],#pylint: disable=E1101
                                    str(self.object.id))
        else:
            url = '/add/%s/' % self.kwargs['fmname'] # pylint: disable=E1101
        return url

    #@transaction.atomic
    def form_valid(self, form):
        'Check the data of a form, save on success'

        gr_list = [elem[1] for elem
                            in self.request.POST.items() # pylint: disable=E1101
                                if str(elem[0]).startswith('data-in-groups-')]
        if len(gr_list) == 0:
            messages.add_message(self.request, # pylint: disable=E1101
                    messages.ERROR,
                    _('At least one group should be selected.'))
            cont = self.get_context_data()
            temp_form = self.get_form_class()
            cont.update({'form': temp_form(initial=form.cleaned_data)})
            return render_to_response('add_data.html', cont,
                    context_instance=template.RequestContext(
                            self.request)) # pylint: disable=E1101
        else:
            gr_objs = Group.objects.filter(pk__in=gr_list)#pylint: disable=E1101
        #link form with extra new link type field
        if  form.cleaned_data.has_key('new_link_type'):
            del form.cleaned_data['new_link_type']
        form.cleaned_data.update(
            {'created_by_id': self.request.user.username, #pylint: disable=E1101
             'classname_id': self.kwargs['fmname']}) # pylint: disable=E1101

        #BEGIN
        try:
            #save new data
            newdata = class_by_name( # pylint: disable=E1101
                    self.kwargs['fmname'])( # pylint: disable=E1101
                            **form.cleaned_data)
            newdata.save()
            self.object = newdata

            #save new data on Desktop
            save_data_ondesktop(self.request, self.object)#pylint: disable=E1101

            #save new data in user's groups
            save_data_ingroups(self.request, # pylint: disable=E1101
                               gr_objs, self.object)

            messages.add_message(self.request, # pylint: disable=E1101
                messages.SUCCESS,
                _('Your added %s Data was successfully saved!'
                               % self.kwargs['fmname'])) # pylint: disable=E1101

        except StandardError:
            import sys
            messages.add_message(self.request, # pylint: disable=E1101
                    messages.ERROR,
                    _('Data creation ERROR: ') + str(sys.exc_info()[1]))
            #ROLLBACK and exit
        #COMMIT

        return redirect(self.get_success_url())

    def get_context_data(self, **kwargs):
        """Prepare context for the form rendering. All desktop groups
           are selected for data adding."""

        context = super(BaseCreateView, self).get_context_data(**kwargs)

        mygroups_data = [(elem, True) for elem in
                          group_desktoplist(self.request)]#pylint: disable=E1101

        context.update(general_context(self.request, # pylint: disable=E1101
                       'Add new data',
                       "Add %s data" % (
                                self.kwargs['fmname']))) # pylint: disable=E1101
        context['mygroups_data'] = mygroups_data
        context['user_action'] = self.get_success_url()
        context['cancel'] = False
        return context
# pylint: enable=R0901,R0904

#------------------------------------------------------------------------------
class BaseUpdateView(UpdateView):
    'Forms for editing and deleting'

    def get_form_class(self):
        'Make a form from a class'

        model = class_by_name(self.kwargs['fmname'])
        form = model_forms.modelform_factory(model)

        # change help_text for fields in derived class, i.e in ReSt class and
        # derived from it
        class_list = [model]
        class_list.extend(model._meta.get_parent_list())
        for mod in class_list:
            opts = mod._meta
            if hasattr(opts, 'help_texts'):
                for key, value in opts.help_texts.iteritems():
                    form.base_fields[key].help_text = value
                return form

        return form

    def get_success_url(self):
        'Prepare the next page url'
        if self.object:
            url = '/edit/%s/%s/' % (self.kwargs['fmname'], str(self.object.id))
        else:
            url = '/'
            messages.add_message(self.request, messages.ERROR,
                 _('Data object is can not be defined'))
        return url

    def get_object(self, queryset=None):
        obj = get_object_or_404(class_by_name(self.kwargs['fmname']),
                                     pk=self.kwargs['pk'])
        return obj

    #@transaction.atomic
    def form_valid(self, form):
        gr_list = [elem[1] for elem in self.request.POST.items()
                                if str(elem[0]).startswith('data-in-groups-')]
        if form.has_changed():
            if len(gr_list) == 0:
                messages.add_message(self.request, messages.ERROR,
                 _('At least one group should be selected.'))
                cont = self.get_context_data()
                temp_form = self.get_form_class()
                cont.update({'form': temp_form(initial=form.cleaned_data)})
                return render_to_response('add_data.html', cont,
                       context_instance=template.RequestContext(self.request))
            else:
                gr_objs = Group.objects.filter( # pylint: disable=E1101
                                pk__in=gr_list)
            if  form.cleaned_data.has_key('new_link_type'):
                del form.cleaned_data['new_link_type']
            form.cleaned_data.update(
                                {'created_by_id': self.request.user.username,
                                'classname_id': self.kwargs['fmname']})

            #BEGIN
            try:
                #mark data as deleted
                obj = class_by_name(self.kwargs['fmname']).objects.get(
                                                           pk=self.kwargs['pk'])
                obj.deleted_on = datetime.datetime.now()
                obj.deleted_by_id = self.request.user.username
                obj.save()
                obj_id = obj.id
                #and delete the object from all desktops
                class_by_name('DeskTop').objects.filter(
                                                 base=obj).delete() #self.object
                links_list = class_by_name('Link').objects.filter(
                   Q(subject=obj_id) | Q(property=obj_id) | Q(link_type=obj_id))
                messages.add_message(self.request, messages.INFO,
                    _('%s data (%s) is marked as deleted'
                       % (self.kwargs['fmname'], obj)))
                #save edited data as new
                new_data = class_by_name(self.kwargs['fmname']).objects.create(
                                                    **form.cleaned_data)

                #mark links as deleted and save new links on new(edited) data
                #for LinkType data only, mark links as deleted,
                # do not add new links
                new_links_list = mark_save_links(self.request, links_list,
                                                 obj_id, new_data)

                #save new data on desktop
                self.object = new_data
                save_data_ondesktop(self.request, self.object)

                #save new links on desktop
                for link in new_links_list:
                    save_data_ondesktop(self.request, link)

                #save new data in user's groups
                save_data_ingroups(self.request, gr_objs, self.object,
                                   new_links_list)

                messages.add_message(self.request, messages.INFO,
                        _(u"%s data (%s) and proper links are edited "
                           "and saved on desktop. Data also was successfully "
                           "added in your groups!"
                             %(self.kwargs['fmname'], self.object)))
            except StandardError:
                import sys
                messages.add_message(self.request, messages.ERROR,
                 _('Data updating ERROR: ') + str(sys.exc_info()[1]))
                #ROLLBACK and exit
            #COMMIT

            return redirect(self.get_success_url())
        return redirect(self.get_success_url())

    def get_context_data(self, **kwargs):
        context = super(BaseUpdateView, self).get_context_data(**kwargs)

        mygroups_desktop = group_desktoplist(self.request)
        groupdata_list = [el.group for el in
              class_by_name('DataGroup').objects.filter(data=self.kwargs['pk'])]
        mygroups_data = []
        for elem in mygroups_desktop:
            if elem.group in groupdata_list:
                mygroups_data.append((elem, True))
            else:
                mygroups_data.append((elem, False))

        context.update(general_context(self.request, 'Edit data',
                "Edit %s data (id=%s)" % (self.kwargs['fmname'],
                                          self.kwargs['pk'])))
        context['mygroups_data'] = mygroups_data
        context['user_action'] = self.get_success_url()
        return context

#------------------------------------------------------------------------------
class DecoratorChainingMixin(object):
    "Define decorators mixin"

    def dispatch(self, *args, **kwargs):
        "Decorators are applied to this dispatcher"

        decorators = getattr(self, 'decorators', [])
        base = super(DecoratorChainingMixin, self).dispatch

        base_decors = [login_required,
                       never_cache,
                       #cache_control(must_revalidate=True, max_age=3600),
                        #csrf_protect
                       ]
        base_decors.extend(decorators)

        for decorator in base_decors:
            base = decorator(base)
        return base(*args, **kwargs)

#------------------------------------------------------------------------------
#@cache_control(must_revalidate=True, max_age=3600)
#@csrf_protect
@login_required
def index(request):
    """Home page"""

    return render_to_response('index.html',
                    general_context(request, 'labman2 Home', 'labman2 Home'),
                    context_instance=template.RequestContext(request))


#------------------------------------------------------------------------------
class GroupListView(DecoratorChainingMixin, ListView):
    'Generator class for user group list'

    context_object_name = "data_list"
    template_name = "data_list.html"

    def get_queryset(self):
        group_desk = [el.group for el in group_desktoplist(self.request)]
        obj_list = class_by_name('UserGroupPerm').objects.filter(
                        user=self.request.user).exclude(group__in=group_desk)
        gr_list = []

        for elem in obj_list:
            if not elem.write:
                gr_list.append((elem.group, 'no add permission'))
            else:
                gr_list.append((elem.group, 'checkbox'))

        for elem in group_desk:
            if elem in group_desk:
                gr_list.append((elem, 'on desktop'))

        return gr_list

    def get_context_data(self, **kwargs):
        context = super(self.__class__, self).get_context_data(**kwargs)
        context.update(general_context(self.request, 'Group List',
                                        'List of your groups'))
        context.update({'action': '/adddesktop/GroupDeskTop/'})
        context.update({'mygroups_desktop': group_desktoplist(self.request)})
        context.update({'title': 'Groups'})
        return context

#------------------------------------------------------------------------------
class ClassListView(DecoratorChainingMixin, ListView):
    'Generator class for user class list'

    context_object_name = "data_list"
    template_name = "data_list.html"
    #model = class_by_name('Classes')

    def get_queryset(self):
        cls_desk = [el.classname for el in classes_desktop(self.request)]
        obj_list = class_by_name('Classes').objects.all()
        cls_list = []

        for elem in obj_list:
            if elem in cls_desk:
                cls_list.append((elem, 'on desktop'))
            else:
                cls_list.append((elem, 'checkbox'))

        return cls_list


    def get_context_data(self, **kwargs):
        context = super(self.__class__, self).get_context_data(**kwargs)
        context.update(general_context(self.request, 'Class List',
                                        'List of classes'))
        context.update({'action': '/adddesktop/ClassDeskTop/'})
        context.update({'title': 'Classes'})
        return context

#------------------------------------------------------------------------------
class DataGroupCreateView(DecoratorChainingMixin, BaseCreateView):
    'Generate forms for creating new datagroup items'

    template_name = 'add_datagroup.html'

    def get_form_class(self):
        """Make a form from a class. Group select list includes desktop groups,
           Data select list includes data from desktop.
        """
        model = class_by_name('DataGroup')
        form = model_forms.modelform_factory(model)
        grs = [elem.group_id for elem in group_desktoplist(self.request)]
        objs = [elem[0].base_id for elem in desktoplist(self.request)]
        form.base_fields['group'].queryset = \
                    Group.objects.filter(id__in=grs) # pylint: disable=E1101
        form.base_fields['data'].queryset = class_by_name(
                                             'Base').objects.filter(id__in=objs)
        return form

    #@transaction.atomic
    def form_valid(self, form):
        'Check the data of a form, save on success'
        form.cleaned_data.update({'created_by_id': self.request.user.username,
                                  'classname_id': 'DataGroup'})
        #BEGIN
        try:
            newdata = class_by_name('DataGroup')(**form.cleaned_data)
            newdata.save()
            self.object = newdata

            #save DataGroup on desktop
            save_data_ondesktop(self.request, self.object)

            #save DataGroup in admin group
            adm_list = Group.objects.filter(name='Admin') #pylint: disable=E1101
            save_data_ingroups(self.request, adm_list, newdata)
            messages.add_message(self.request, messages.SUCCESS,
              _('Your DataGroup was successfully saved and you can edit it!'))
        except StandardError:
            import sys
            messages.add_message(self.request, messages.ERROR,
            _('DataGroup data creation ERROR: ') + str(sys.exc_info()[1]))
            #ROLLBACK and exit
        #COMMIT
        return redirect(self.get_success_url())

    def get_context_data(self, **kwargs):
        'Prepare context for the form rendering'
        context = super(self.__class__, self).get_context_data(**kwargs)
        context.update(general_context(self.request, 'DataGRoup',
                                        'Add DataGroup data'))
        context['user_action'] = self.get_success_url()
        return context

#------------------------------------------------------------------------------
class UserGroupPermView(DecoratorChainingMixin, ListView):
    'Generator class for user group list'

    context_object_name = "usergrperm_list"
    template_name = "perms_list.html"

    def get_queryset(self):
        grps_ondesk = [el.group.id for el in group_desktoplist(self.request)]
        if self.request.user.is_superuser:
            groups_list = Group.objects.all() # pylint: disable=E1101
        else:
            groups_list = [el.group for el in
                            class_by_name('UserGroupPerm').objects.filter(
                                       user=self.request.user.id, master=True,
                                       group__in=grps_ondesk)]
        gr_usersperm_list = []
        for elem in groups_list:
            usersperm = class_by_name(
                                     'UserGroupPerm').objects.filter(group=elem)
            gr_usersperm_list.append((elem, usersperm))
        return gr_usersperm_list

    def get_context_data(self, **kwargs):
        context = super(self.__class__, self).get_context_data(**kwargs)
        context.update(general_context(self.request, 'GroupUsersPermissions',
                                    'List of Groups, Users and Permissions'))
        return context

#------------------------------------------------------------------------------
class UserGroupPermCreateView(DecoratorChainingMixin, CreateView):
    'Generate forms for creating new user permissions in group'

    template_name = 'add_perm.html'
    #decorators = [transaction.atomic]

    def get_form_class(self):
        """Makes a form from a class. Group select list contains only groups
           where user is master.
        """
        model = class_by_name('UserGroupPerm')
        form = model_forms.modelform_factory(model)
        grps_ondesk = [el.group.id for el in group_desktoplist(self.request)]
        if self.request.user.is_superuser:
            grs = [el.id for el in Group.objects.all()] # pylint: disable=E1101
        else:
            usr_gr_objs = class_by_name('UserGroupPerm').objects.filter(
                                       user=self.request.user.id, master=True,
                                       group__in=grps_ondesk)
            grs = [el.group.id for el in usr_gr_objs]
        group_queryset = Group.objects.filter(id__in=grs)
        if group_queryset.exists():
            form.base_fields['group'].queryset = group_queryset
        else:
            form.base_fields['group'].help_text = 'no permissions'
        return form

    def get_success_url(self):
        'Prepare the next page url'
        if self.object:
            url = '/permingroups/'
        else:
            url = '/add/UserGroupPerm/'
        return url

    #@transaction.atomic
    def form_valid(self, form):
        'Save UserGroupPermissions'

        form.cleaned_data.update({'created_by_id': self.request.user.username,
                                  'classname_id': 'UserGroupPerm'})
        #BEGIN
        try:
            newdata = class_by_name('UserGroupPerm')(**form.cleaned_data)
            newdata.save()
            self.object = newdata

            #save UserGroupPerm data in Admin group
            adm_list = Group.objects.filter(name='Admin') #pylint: disable=E1101
            save_data_ingroups(self.request, adm_list, newdata)
            messages.add_message(self.request, messages.SUCCESS,
               _('Added Permissions was successfully saved!' \
                 'UserGroupPerm Data is added in Admin group.'))
        except StandardError:
            import sys
            messages.add_message(self.request, messages.ERROR,
              _('UserGroupPerm data creation ERROR: ')+str(sys.exc_info()[1]))
            #ROLLBACK and exit
        #COMMIT
        return redirect(self.get_success_url())

    def get_context_data(self, **kwargs):
        'Prepare context for the form rendering'
        context = super(UserGroupPermCreateView,
                        self).get_context_data(**kwargs)
        context.update(general_context(self.request, 'UserGroupPerm',
                                    'Add permisions in your group'))
        context['user_action'] = self.get_success_url()
        return context

#------------------------------------------------------------------------------
class UserGroupPermUpdateView(DecoratorChainingMixin, BaseUpdateView):
    """
        Generate forms for editing user permissions in group. Only master can
        edit user members permission in the group.
    """

    template_name = 'edit_perm.html'
    #decorators = [transaction.atomic]

    def get_queryset(self):
        'Make a gueryset for user field (UserGroupPerm object, members list).'
        ugp_obj = class_by_name('UserGroupPerm').objects.get(
                                                           pk=self.kwargs['pk'])
        usrs = [elem.user_id for elem in
                class_by_name('UserGroupPerm').objects.filter(
                                                           group=ugp_obj.group)]
        membs = User.objects.filter(id__in=usrs)
        return (ugp_obj, membs)

    def get_form_class(self):
        'Make the UserGroupPerm form. Only members of the group in User field.'
        model = class_by_name('UserGroupPerm')
        form = model_forms.modelform_factory(model)
        form.base_fields['user'].queryset = self.get_queryset()[1]
        form.base_fields['group'].queryset = \
            Group.objects.filter( # pylint: disable=E1101
                                id=self.get_queryset()[0].group_id)
        return form

    def form_valid(self, form):
        messages.add_message(self.request, messages.SUCCESS,
              _('Permissions is successfully changed!'))
        return UpdateView.form_valid(self, form)

    def form_invalid(self, form):
        if (form._errors.has_key('__all__') and
              form._errors['__all__'].__repr__() == repr([u'PERMIS_DELETED'])):
            return redirect(u"/destroy/UserGroupPerm/%s/" %self.kwargs['pk'])
        return self.render_to_response( # pylint: disable=E1101
                      self.get_context_data(form=form)) # pylint: disable=E1101

    def get_context_data(self, **kwargs):
        'Prepare context for the form rendering'
        context = super(UserGroupPermUpdateView,
                        self).get_context_data(**kwargs)
        context.update(general_context(self.request, 'UserGroupPerm',
            "Edit permisions in %s group" % self.get_queryset()[0].group))

        obj = class_by_name('UserGroupPerm').objects.filter(
                                         user=self.request.user,
                                         group=self.get_queryset()[0].group,
                                         master=True)
        context['master'] = True if obj.exists() else False
        context['user_action'] = self.get_success_url()
        return context
